/*
 * Copyright (C) 2000 - 2024 Silverpeas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * As a special exception to the terms and conditions of version 3.0 of
 * the GPL, you may redistribute this Program in connection with Free/Libre
 * Open Source Software ("FLOSS") applications as described in Silverpeas's
 * FLOSS exception.  You should have received a copy of the text describing
 * the FLOSS exception, and it is also available here:
 * "https://www.silverpeas.org/legal/floss_exception.html"
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
package org.silverpeas.core.contribution.attachment.webdav;

import org.silverpeas.core.contribution.attachment.model.SimpleDocument;
import org.silverpeas.core.contribution.attachment.webdav.impl.WebdavContentDescriptor;

import javax.jcr.RepositoryException;
import javax.jcr.Session;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Optional;

public interface WebdavRepository {
  /**
   * Create a new node for the specified attachment so that the file may be accessed through webdav.
   * For an attachment, it can exist in webdav one, and only one, content language of the
   * attachment.
   * @param session the JCR session.
   * @param attachment the attachment.
   * @throws RepositoryException if an error occurs while creating the node in the JCR.
   * @throws IOException if an error occurs while saving the attachment content.
   */
  void createAttachmentNode(Session session, SimpleDocument attachment)
      throws RepositoryException, IOException;

  /**
   * Delete the node associated to the specified attachment. All contents will be removed. If a
   * specific content (language) must be removed, then use
   * {@link #deleteAttachmentContentNode(Session, SimpleDocument, String)} method.
   * @param session the JCR session.
   * @param attachment the attachment.
   * @throws RepositoryException if an error occurs while deleting the node in the JCR.
   */
  void deleteAttachmentNode(Session session, SimpleDocument attachment) throws RepositoryException;

  /**
   * Delete the node associated to the specified language content attachment.
   * @param session the JCR session.
   * @param attachment the attachment.
   * @param language the aimed language content to delete.
   * @throws RepositoryException if an error occurs while creating the content node in the JCR.
   */
  void deleteAttachmentContentNode(Session session, SimpleDocument attachment, String language)
      throws RepositoryException;

  /**
   * Update the file content of the specified attachment without modifying its metadata.
   * @param session the JCR session.
   * @param attachment the attachment for which the file content will be updated with the related
   * webdav content.
   * @throws RepositoryException if an error occurs while updating the node content in the JCR.
   * @throws IOException if an error occurs while updating the attachment content.
   */
  void updateAttachmentBinaryContent(Session session, SimpleDocument attachment)
      throws RepositoryException, IOException;

  /**
   * Update the node using the {@link SimpleDocument}. For an attachment, it can exist in webdav
   * one, and only one, content language of the attachment.
   * @param session the JCR session.
   * @param attachment the attachment.
   * @throws RepositoryException if an error occurs while updating the node in the JCR.
   * @throws IOException if an error occurs while updating the attachment content.
   */
  void updateNodeAttachment(Session session, SimpleDocument attachment)
      throws RepositoryException, IOException;

  /**
   * Move the specified attachment to the specified component instance id.
   * @param session the JCR session.
   * @param attachment the attachment to move to another component instance identifier.
   * @param targetComponentInstanceId the identifier of the target component instance.
   * @throws RepositoryException if an error occurs while moving the node in the JCR.
   */
  void moveNodeAttachment(Session session, SimpleDocument attachment,
      String targetComponentInstanceId) throws RepositoryException;

  /**
   * Indicate if the node for the specified attachment is currently locked (for example by Office in
   * the case of a webdav online edition).
   * @param session the JCR session.
   * @param attachment the attachment.
   * @return true if the node is locked - false otherwise.
   */
  boolean isNodeLocked(Session session, SimpleDocument attachment) throws RepositoryException;

  /**
   * Unlock the node for the specified attachment is currently locked (for example by Office in
   * the case of a webdav online edition).
   * <p>
   *   Nothing is done if node is already unlocked.
   * </p>
   * @param session the JCR session.
   * @param attachment the attachment.
   * @return true if the node has been effectively locked - false otherwise.
   */
  boolean unlockLockedNode(Session session, SimpleDocument attachment) throws RepositoryException;

  /**
   * Gets the current content edition language of the specified attachment. If several webdav
   * document exists (several content languages), then the one which has the highest modified date
   * is taken into account.
   * @param session the JCR session.
   * @param attachment the attachment.
   * @return the ISO-631 code of the content edition language if the specified attachment exists in
   * the webdav repository, null otherwise.
   * @throws RepositoryException if an error occurs while getting the language of the content.
   */
  String getContentEditionLanguage(Session session, SimpleDocument attachment)
      throws RepositoryException;

  /**
   * Gets the current content edition size of the specified attachment. If several webdav document
   * exists (several content languages), then the one which has the highest modified date is taken
   * into account.
   * @param session the JCR session.
   * @param attachment the attachment.
   * @return the content edition size in bytes if the specified attachment exists in the webdav
   * repository, -1 otherwise.
   * @throws RepositoryException if an error occurs while getting the size of the content.
   */
  long getContentEditionSize(Session session, SimpleDocument attachment)
      throws RepositoryException;

  /**
   * Gets the current webdav descriptor of the specified attachment. If several webdav document
   * exists (several content languages), then the one which has the highest modified date is taken
   * into account.
   * @param session the JCR session.
   * @param attachment the attachment.
   * @return the optional content edition webdav descriptor if the specified attachment exists in
   * the webdav repository.
   * @throws RepositoryException on JCR access error.
   */
  Optional<WebdavContentDescriptor> getDescriptor(Session session, SimpleDocument attachment)
      throws RepositoryException;

  /**
   * Updates a document content into the WEBDAV repository.
   * <p>
   * If several webdav document exists (several content languages), then the one which has the
   * highest modified date is taken into account.
   * </p>
   * @param session the JCR session.
   * @param document the aimed document.
   * @param input the data to write.
   * @throws RepositoryException if an error occurs while updating the content.
   */
  void updateContentFrom(Session session, SimpleDocument document, InputStream input)
      throws RepositoryException, IOException;

  /**
   * Reads a document content from the WEBDAV repository and writes it into given output.
   * <p>
   * If several webdav document exists (several content languages), then the one which has the
   * highest modified date is taken into account.
   * </p>
   * @param session the JCR session.
   * @param document the aimed document.
   * @param output the stream to write into.
   * @throws RepositoryException if an error occurs while loading the content.
   */
  void loadContentInto(Session session, SimpleDocument document, OutputStream output)
      throws RepositoryException, IOException;
}